/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2008-2011, Salzburg Research. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither the name of the KiWi Project nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Contributor(s):
 * sschaffe
 *
 * File Info:
 * User: sschaffe
 * Date: 2011/01/18
 * Time: 11:12
 *
 * Project: KiWi2, kiwi-core module
 */

package kiwi.core.services.versioning;

import kiwi.core.api.persistence.PersistenceService;
import kiwi.core.api.transaction.TransactionData;
import kiwi.core.api.versioning.VersioningService;
import kiwi.core.model.rdf.KiWiNode;
import kiwi.core.model.user.KiWiUser;
import kiwi.core.model.versioning.Version;
import kiwi.core.qualifiers.event.transaction.AfterCommit;
import kiwi.core.qualifiers.user.CurrentUser;
import org.slf4j.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import java.util.List;

/**
 * Add file description here!
 * <p/>
 * User: sschaffe
 */
@Named("kiwi.core.versioningService")
@ApplicationScoped
public class VersioningServiceImpl implements VersioningService {


    @Inject
    private Logger log;

    @Inject
    private PersistenceService persistenceService;


    @Inject @CurrentUser
    private KiWiUser currentUser;

    /**
     * Create a new version using the transaction data passed as argument. The method is implemented as an observer
     * that is listening to the transaction AfterCommit event and takes the committed transaction data to create
     * and store a new version entity referring to the added and removed nodes, the added and removed triples and
     * the added and removed namespaces in the transaction.
     *
     * @param data
     * @see kiwi.core.model.versioning.Version
     */
    @Override
    public void createVersion(@Observes @AfterCommit TransactionData data) {

        if(data.getAddedNodes().size()   + data.getRemovedNodes().size() +
                data.getAddedTriples().size() + data.getRemovedTriples().size() +
                data.getAddedNS().size()      + data.getRemovedNS().size() > 0) {


            // open a new entity manager transaction
            EntityManager entityManager = persistenceService.getEntityManager();
            EntityTransaction tx = entityManager.getTransaction();

            tx.begin();

            Version version = new Version();
            version.setAddedNodes(data.getAddedNodes());
            version.setRemovedNodes(data.getRemovedNodes());
            version.setAddedTriples(data.getAddedTriples());
            version.setRemovedTriples(data.getRemovedTriples());
            version.setAddedNamespaces(data.getAddedNS());
            version.setRemovedNamespaces(data.getRemovedNS());
            version.setCreator(currentUser);

            entityManager.persist(version);

            // commit the entity manager transaction
            entityManager.flush();
            tx.commit();
            persistenceService.closeEntityManager(entityManager);


        } else {
            log.debug("not creating new version, as transaction data is empty");
        }
    }

    /**
     * List all versions that currently exist in the KiWi system.
     *
     * @return
     */
    @Override
    public List<Version> listVersions() {
        EntityManager entityManager = persistenceService.getEntityManager();
        EntityTransaction tx = entityManager.getTransaction();

        try {
            tx.begin();
            Query query = entityManager.createNamedQuery("versioning.listVersions");

            return query.getResultList();
        } finally {
            tx.commit();
            persistenceService.closeEntityManager(entityManager);
        }
    }

    /**
     * List all versions in the KiWi system that affect the KiWiNode passed as argument. The list will include all
     * versions that have the KiWiNode either in the set of added or in the set of removed nodes. The list will be
     * ordered in decreasing order sorted by time.
     *
     * @param node
     * @return
     */
    @Override
    public List<Version> listVersions(KiWiNode node) {
        EntityManager entityManager = persistenceService.getEntityManager();
        EntityTransaction tx = entityManager.getTransaction();

        try {
            tx.begin();
            Query query = entityManager.createNamedQuery("versioning.listVersionsByNode");
            query.setParameter("node",node);

            return query.getResultList();
        } finally {
            tx.commit();
            persistenceService.closeEntityManager(entityManager);
        }
    }

    /**
     * List "limit" versions in the KiWi system that affect the KiWiNode passed as argument, offset by the given offset.
     * The list will include all versions that have the KiWiNode either in the set of added or in the set of removed
     * nodes. The list will be ordered in decreasing order sorted by time.
     *
     * @param node
     * @return
     */
    @Override
    public List<Version> listVersions(KiWiNode node, int offset, int limit) {
        EntityManager entityManager = persistenceService.getEntityManager();
        EntityTransaction tx = entityManager.getTransaction();

        try {
            tx.begin();
            Query query = entityManager.createNamedQuery("versioning.listVersionsByNode");
            query.setParameter("node",node);
            query.setMaxResults(limit);
            query.setFirstResult(offset);

            return query.getResultList();
        } finally {
            tx.commit();
            persistenceService.closeEntityManager(entityManager);
        }
    }
}
